#include<iostream>
#include<vector>
#include<unistd.h>
#include"task.hpp"
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;
enum {
    UsageError = 1,//参数错误 
    ArgError,//数量错误
    PipeError //创建管道错误
};
void Usage(const std::string& proc)
{
    cout<<"Usage:" <<proc <<"subprocess-num" <<endl;
}
class Channel
{
    public:
        Channel(int wfd,pid_t sub_id,const string& name)
        :_wfd(wfd),_sub_process_id(sub_id),_name(name)
        {}
        string name()
        {
            return _name;
        }
        pid_t pid()
        {
            return _sub_process_id;
        }
        int wfd()
        {
            return _wfd;
        }
        void Close() //关闭写段
        {
            close(_wfd);
        }
        void Print_Debug()
        {
            cout << "_wfd: " << _wfd;
            cout << ",_sub_process_id: " << _sub_process_id;
            cout << ", _name: " << _name << endl;
        }
        ~Channel()
        {
        }
    private:
        int _wfd;//管道的写端
        pid_t _sub_process_id;//子进程id
        string _name;
    };
class ProcessPool
{
    public:
        ProcessPool(int sub_process_num)
        :_sub_process_num(sub_process_num)
        {}
        ~ProcessPool(){}
        int Creat_Process(work_t work)
        {
            std::vector<int> fds;
            for(int number = 0; number < _sub_process_num; number++)
            {
                int pipefd[2]{0};
                int n = pipe(pipefd); //创建管道
                if(n < 0)
                {
                    return PipeError;                    
                }
                pid_t id = fork();//创建子进程
                if(id == 0)
                {
                    //子进程
                    //防止文件描述符子进程被重复继承
                    if(!fds.empty())
                    {
                        std::cout<<"close fd:";
                        for(auto fd : fds)
                        {
                            close(fd);
                            std::cout<< fd <<"";
                        }
                        std::cout<<std::endl;
                    }
                    //child -> r
                    close(pipefd[1]);//关闭写端
                    dup2(pipefd[0], 0);//程序的标准输入被重定向到管道的读取端，从管道中读取数据
                    work(pipefd[0]);
                    exit(0);
                }
                //父进程
                //father -> w
                string name = "channel-" + to_string(number);
                close(pipefd[0]);//关闭父进程读端
                channels.push_back(Channel(pipefd[1],id,name));
                //保存父进程的wfd
                fds.push_back(pipefd[1]);
            }
            return 0;
        }
        void Debug()
        {
            for(auto channel : channels)
            {
                channel.Print_Debug();
            }
        }
        int NextChannel()
        {
            static int next = 0;
            int c = next;
            next++;
            next %= channels.size();
            return c;
        }
        void SendTaskCode(int index,uint32_t code)
        {
            cout << "send code: " << code << " to " << channels[index].name() << " sub prorcess id: " << channels[index].pid() << endl;
            write(channels[index].wfd(),&code,sizeof(code));//向管道中写入
        }
        // 让子进程全部退出，只需要关闭所有的Channel w即可！
        void KillAll()
        {
            for(auto channel : channels)
            {
                channel.Close();//关闭管道写端
                pid_t id = channel.pid();
                pid_t rid = waitpid(id,nullptr,0);//释放子进程资源
                if(rid == id)
                {
                    std::cout << "wait sub process: " << id << " success..." << std::endl;
                }
                std::cout << channel.name() << " close done" << " sub process quit now : " << channel.pid() << std::endl;
            }
        }
    private:
        int _sub_process_num;
        vector<Channel> channels;
};
void CtrlProcessPool(ProcessPool* ptr,int n)
{
    while(n)
    {
        //1. 选择一个通道
        int channel = ptr->NextChannel();
        //2. 选择一个任务
        uint32_t code = NextTask();
        //3. 发送任务：向管道写端写入
        ptr->SendTaskCode(channel,code);
        sleep(1);
        n--;
    }
}
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);//使用说明
        return UsageError;
    }
    int sub_process_num = std::stoi(argv[1]);
    if(sub_process_num < 0)
    {
        return ArgError;
    }
    srand((uint32_t)time(nullptr));
    //1. 创建通信信道和子进程
    ProcessPool* processpool_ptr = new ProcessPool(sub_process_num);//创建ProcessPool对象指针
    processpool_ptr->Creat_Process(worker);//创建子进程和通信管道 
    processpool_ptr->Debug(); 
    //2. 控制进程
    CtrlProcessPool(processpool_ptr,10);//执行10个任务
    processpool_ptr->KillAll();
    delete processpool_ptr;
    return 0;
}